//
//  HWStability.m
//  OCDome
//
//  Created by 李含文 on 2021/3/31.
//  Copyright © 2021 李含文. All rights reserved.
//

#import "HWStability.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
#import <objc/message.h>

#define ExcepitionHappenedEnd   @"================================================================"
#define ExcepitionHappenedStart @"========================⚠️⚠️⚠️⚠️⚠️⚠️⚠️========================="
@protocol HWStabilityProtocol <NSObject>

@required
/// 交换方法
+ (void)hw_swizzleMethod;

@end

void hw_exchangeInstanceMethod(Class cls, SEL originSelector, SEL swizzledSelector) {
    if (!cls) return;
    Method originalMethod = class_getInstanceMethod(cls, originSelector);
    Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
    BOOL didAddMethod =  class_addMethod(cls,
                                         originSelector,
                                         method_getImplementation(swizzledMethod),
                                         method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(cls,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        class_replaceMethod(cls,
                            swizzledSelector,
                            class_replaceMethod(cls,
                                                originSelector,
                                                method_getImplementation(swizzledMethod),
                                                method_getTypeEncoding(swizzledMethod)),
                            method_getTypeEncoding(originalMethod));
    }
}

void hw_exchangeClassMethod(Class cls, SEL originSelector, SEL swizzledSelector) {
    if (!cls) return;
    Class metacls = objc_getMetaClass(NSStringFromClass(cls).UTF8String);
    Method originalMethod = class_getClassMethod(cls, originSelector);
    Method swizzledMethod = class_getClassMethod(cls, swizzledSelector);
    BOOL didAddMethod = class_addMethod(metacls,
                                        originSelector,
                                        method_getImplementation(swizzledMethod),
                                        method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(metacls,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
//MARK: - Hook
@implementation NSObject (HWHook)
+ (void)hw_exchangeInstanceMethod:(SEL)originSelector withSEL:(SEL)swizzledSelector {
    Class class = [self class];
    hw_exchangeInstanceMethod(class, originSelector, swizzledSelector);
}

+ (void)hw_exchangeClassMethod:(SEL)originSelector withSEL:(SEL)swizzledSelector {
    Class class = [self class];
    hw_exchangeClassMethod(class, originSelector, swizzledSelector);
}
@end

//MARK: - HWStability
void hw_handleErrorWithException(NSException * exception);
@interface HWStability()
{
    // 保护交换方法的安全
    dispatch_semaphore_t _swizzleLock;
}
@property (nonatomic, strong) NSMutableArray<Class> *protectedClassArray;

+ (void)handleErrorWithException:(NSException *)exception;
@end

void hw_handleErrorWithException(NSException * exception) {
    [HWStability handleErrorWithException:exception];
}
@implementation HWStability

static HWStability *_instance = nil;
/// 单例模式
+ (instancetype)shared {
    return [[self alloc] init];
}

+ (id)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!_instance) {
            _instance = [super allocWithZone:zone];
        }
    });
    return _instance;
}

- (nonnull id)copyWithZone:(nullable NSZone *)zone {
    return _instance;
}

- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {
    return _instance;
}

- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super init];
        [_instance initData];
        _swizzleLock = dispatch_semaphore_create(1);
    });
    return _instance;
}

- (void)initData {
    Class array = [NSArray class];
    [self addClassToArray:array];
    
    Class mutableArray = [NSMutableArray class];
    [self addClassToArray:mutableArray];
    
    Class dictionary = [NSDictionary class];
    [self addClassToArray:dictionary];
    
    Class mutableDictionary = [NSMutableDictionary class];
    [self addClassToArray:mutableDictionary];
    
    Class string = [NSString class];
    [self addClassToArray:string];
    
    Class mutableString = [UIView class];
    [self addClassToArray:mutableString];
    
    Class view = [UIView class];
    [self addClassToArray:view];
    
    Class timer = [NSTimer class];
    [self addClassToArray:timer];
    
    Class object = [NSObject class];
    [self addClassToArray:object];
}

- (void)openProtection {
    dispatch_semaphore_wait(_swizzleLock, DISPATCH_TIME_FOREVER);
    [self.protectedClassArray enumerateObjectsUsingBlock:^(Class  _Nonnull cls, NSUInteger idx, BOOL * _Nonnull stop) {
        [cls performSelector:@selector(hw_swizzleMethod)];
    }];
    dispatch_semaphore_signal(_swizzleLock);
}

- (void)addClassToArray:(Class)cls {
    // 判断是否遵守了此协议
    if ([cls conformsToProtocol:@protocol(HWStabilityProtocol)]) {
        [self.protectedClassArray addObject:cls];
    };
}

- (NSMutableArray *)protectedClassArray {
    if (!_protectedClassArray) {
        _protectedClassArray = [[NSMutableArray alloc] init];
    }
    return _protectedClassArray;
}

+ (void)handleErrorWithException:(NSException *)exception {
    // 堆栈数据
    NSArray *callStackSymbolsArr     = [NSThread callStackSymbols];
    // 获取在哪个类的哪个方法中实例化的数组  字符串格式 -[类名 方法名]  或者 +[类名 方法名]
    NSString *mainCallStackSymbolMsg = [self getMainCallStackSymbolMessageWithCallStackSymbols:callStackSymbolsArr];
    
    if (mainCallStackSymbolMsg == nil)  mainCallStackSymbolMsg = @"崩溃方法定位失败,请您查看函数调用栈来排查错误原因";
    
    NSString *errorName = exception.name;
    NSString *errorReason = exception.reason;
    // errorReason 可能为 -[__NSCFConstantString avoidCrashCharacterAtIndex:]: Range or index out of bounds
    errorReason = [errorReason stringByReplacingOccurrencesOfString:@"avoidCrash" withString:@""];
    
    // 拼接错误信息
    NSString *errorPlace = [NSString stringWithFormat:@"崩溃地址:%@",mainCallStackSymbolMsg];
    NSString *logErrorMessage = [NSString stringWithFormat:@"\n%@\n%@\n%@\n%@\n",ExcepitionHappenedStart, errorName, errorReason, errorPlace];
    logErrorMessage = [NSString stringWithFormat:@"%@\n%@\n",logErrorMessage,ExcepitionHappenedEnd];
    
    if (HWStability_isShowLog) {
        NSLog(@"%@",logErrorMessage);
#if DEBUG
        UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:errorName message:errorReason preferredStyle:UIAlertControllerStyleAlert];
        [alertVC addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];
        [HW_MainWindow().rootViewController presentViewController:alertVC animated:YES completion:nil];
        //        [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertVC animated:YES completion:nil];
#endif
    }
    //    NSDictionary *errorInfoDic = @{
    //                                   @"errorName"        : errorName,
    //                                   @"errorReason"      : errorReason,
    //                                   @"errorPlace"       : errorPlace,
    //                                   @"exception"        : exception,
    //                                   @"callStackSymbols" : callStackSymbolsArr
    //                                   };
    //
    //    // 将错误信息放在字典里，用通知的形式发送出去
    //    dispatch_async(dispatch_get_main_queue(), ^{
    //        [[NSNotificationCenter defaultCenter] postNotificationName:kExcepitionHappenedNotification object:nil userInfo:errorInfoDic];
    //    });
}

/**
 简化堆栈信息
 @param callStackSymbols 详细堆栈信息
 @return 简化之后的堆栈信息
 */
+ (NSString *)getMainCallStackSymbolMessageWithCallStackSymbols:(NSArray<NSString *> *)callStackSymbols
{
    // mainCallStackSymbolMsg的格式为   +[类名 方法名]  或者 -[类名 方法名]
    __block NSString *mainCallStackSymbolMsg = nil;
    
    // 匹配出来的格式为 +[类名 方法名]  或者 -[类名 方法名]
    NSString *regularExpStr = @"[-\\+]\\[.+\\]";
    NSRegularExpression *regularExp = [[NSRegularExpression alloc] initWithPattern:regularExpStr
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:nil];
    for (int index = 2; index < callStackSymbols.count; index++) {
        
        NSString *callStackSymbol = callStackSymbols[index];
        [regularExp enumerateMatchesInString:callStackSymbol
                                     options:NSMatchingReportProgress
                                       range:NSMakeRange(0, callStackSymbol.length)
                                  usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
            
            if (result) {
                NSString *tempCallStackSymbolMsg = [callStackSymbol substringWithRange:result.range];
                
                NSString *className = [tempCallStackSymbolMsg componentsSeparatedByString:@" "].firstObject;
                className           = [className componentsSeparatedByString:@"["].lastObject;
                
                NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(className)];
                if (![className hasSuffix:@")"] && bundle == [NSBundle mainBundle]) {
                    mainCallStackSymbolMsg = tempCallStackSymbolMsg;
                    
                }
                *stop = YES;
            }
            
        }];
        
        if (mainCallStackSymbolMsg.length) break;
    }
    return mainCallStackSymbolMsg;
}
@end




//MARK: - NSArray
@interface NSArray (HWStability)<HWStabilityProtocol>
@end

@implementation NSArray (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //=================
        //     类方法交换
        //=================
        [NSArray hw_exchangeClassMethod:@selector(arrayWithObject:)        withSEL:@selector(safeArrayWithObject:)];
        [NSArray hw_exchangeClassMethod:@selector(arrayWithObjects:count:) withSEL:@selector(safeArrayWithObjects:count:)];
        
        //===================
        //     实例方法交换
        //===================
        // __NSArray0
        Class clsArray0 = objc_getClass("__NSArray0");
        hw_exchangeInstanceMethod(clsArray0, @selector(objectAtIndex:),            @selector(safeObjectAtIndex:));
        hw_exchangeInstanceMethod(clsArray0, @selector(subarrayWithRange:),        @selector(safeSubarrayWithRange:));
        hw_exchangeInstanceMethod(clsArray0, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
        
        // __NSArrayI
        Class clsArray1 = objc_getClass("__NSArrayI");
        hw_exchangeInstanceMethod(clsArray1, @selector(objectAtIndex:),            @selector(safeObjectAtIndex:));
        hw_exchangeInstanceMethod(clsArray1, @selector(subarrayWithRange:),        @selector(safeSubarrayWithRange:));
        hw_exchangeInstanceMethod(clsArray1, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
        
        // __NSArrayI_Transfer
        Class clsArrayIT = objc_getClass("__NSArrayI_Transfer");
        hw_exchangeInstanceMethod(clsArrayIT, @selector(objectAtIndex:),            @selector(safeObjectAtIndex:));
        hw_exchangeInstanceMethod(clsArrayIT, @selector(subarrayWithRange:),        @selector(safeSubarrayWithRange:));
        hw_exchangeInstanceMethod(clsArrayIT, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
        
        
        // above iOS10  __NSSingleObjectArrayI
        Class clsArraySI = objc_getClass("__NSSingleObjectArrayI");
        hw_exchangeInstanceMethod(clsArraySI, @selector(objectAtIndex:),            @selector(safeObjectAtIndex:));
        hw_exchangeInstanceMethod(clsArraySI, @selector(subarrayWithRange:),        @selector(safeSubarrayWithRange:));
        hw_exchangeInstanceMethod(clsArraySI, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
        
        // __NSFrozenArrayM
        Class clsArrayM = objc_getClass("__NSFrozenArrayM");
        hw_exchangeInstanceMethod(clsArrayM, @selector(objectAtIndex:),            @selector(safeObjectAtIndex:));
        hw_exchangeInstanceMethod(clsArrayM, @selector(subarrayWithRange:),        @selector(safeSubarrayWithRange:));
        hw_exchangeInstanceMethod(clsArrayM, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
        
        // __NSArrayReversed
        Class clsArrayR = objc_getClass("__NSArrayReversed");
        hw_exchangeInstanceMethod(clsArrayR, @selector(objectAtIndex:),            @selector(safeObjectAtIndex:));
        hw_exchangeInstanceMethod(clsArrayR, @selector(subarrayWithRange:),        @selector(safeSubarrayWithRange:));
        hw_exchangeInstanceMethod(clsArrayR, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
        
    });
    
}

+ (instancetype)safeArrayWithObject:(id)anObject {
    id array = nil;
    @try {
        array = [self safeArrayWithObject:anObject];
        
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return array;
    }
}

- (id)safeObjectAtIndex:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self safeObjectAtIndex:index];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return object;
    }
}

- (id)safeObjectAtIndexedSubscript:(NSInteger)index {
    id object = nil;
    @try {
        object = [self safeObjectAtIndexedSubscript:index];
    }
    @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    }
    @finally {
        return object;
    }
}

- (NSArray *)safeSubarrayWithRange:(NSRange)range {
    NSArray *array = nil;
    @try {
        array = [self safeSubarrayWithRange:range];
    } @catch (NSException *exception) {
        array = [self safeSubarrayWithRange:NSMakeRange(range.location, self.count - range.location)];
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return array;
    }
}

+ (instancetype)safeArrayWithObjects:(const id [])objects count:(NSUInteger)cnt {
    id array = nil;
    @try {
        array = [self safeArrayWithObjects:objects count:cnt];
    } @catch (NSException *exception) {
        // 把为nil的数据去掉,然后初始化数组
        NSInteger newObjsIndex = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        for (int i = 0; i < cnt; i++) {
            if (objects[i] != nil) {
                newObjects[newObjsIndex] = objects[i];
                newObjsIndex++;
            }
        }
        array = [self safeArrayWithObjects:newObjects count:newObjsIndex];
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return array;
    }
}

@end

@interface NSMutableArray (HWStability)<HWStabilityProtocol>

@end

@implementation NSMutableArray (HWStability)

+ (void)hw_swizzleMethod {
    Class clsArrayM = objc_getClass("__NSArrayM");
    hw_exchangeInstanceMethod(clsArrayM, @selector(addObject:),@selector(safeAddObject:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(objectAtIndex:),        @selector(safeObjectAtIndex:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(objectAtIndexedSubscript:), @selector(safeObjectAtIndexedSubscript:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(insertObject:atIndex:), @selector(safeInsertObject:atIndex:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(removeObjectAtIndex:), @selector(safeRemoveObjectAtIndex:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(replaceObjectAtIndex:withObject:), @selector(safeReplaceObjectAtIndex:withObject:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(removeObjectsInRange:), @selector(safeRemoveObjectsInRange:));
    hw_exchangeInstanceMethod(clsArrayM, @selector(subarrayWithRange:), @selector(safeSubarrayWithRange:));
}

- (void)safeAddObject:(id)anObject {
    @try {
        [self safeAddObject:anObject];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {  }
}

- (id)safeObjectAtIndex:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self safeObjectAtIndex:index];
    } @catch (NSException *exception) {
        object = [self lastObject];
        hw_handleErrorWithException(exception);
    } @finally {
        return  object;
    }
}

- (id)safeObjectAtIndexedSubscript:(NSInteger)index {
    id object = nil;
    @try {
        object = [self safeObjectAtIndexedSubscript:index];
    } @catch (NSException *exception) {
        object = [self lastObject];
        hw_handleErrorWithException(exception);
    } @finally {
        return  object;
    }
    
}

- (void)safeInsertObject:(id)anObject atIndex:(NSUInteger)index {
    @try {
        [self safeInsertObject:anObject atIndex:index];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally { }
}

- (void)safeRemoveObjectAtIndex:(NSUInteger)index {
    @try {
        [self safeRemoveObjectAtIndex:index];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally { }
}


- (void)safeReplaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
    @try {
        [self safeReplaceObjectAtIndex:index withObject:anObject];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally { }
}

- (void)safeRemoveObjectsInRange:(NSRange)range {
    @try {
        [self safeRemoveObjectsInRange:range];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally { }
}

- (NSArray *)safeSubarrayWithRange:(NSRange)range {
    NSArray *array = nil;
    @try {
        array = [self safeSubarrayWithRange:range];
    } @catch (NSException *exception) {
        array = [self safeSubarrayWithRange:NSMakeRange(range.location, self.count - range.location)];
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return array;
    }
}
@end

//MARK: - NSDictionary
@interface NSDictionary (HWStability)<HWStabilityProtocol>
@end
@implementation NSDictionary (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        hw_exchangeClassMethod([self class], @selector(dictionaryWithObject:forKey:), @selector(safeDictionaryWithObject:forKey:));
        hw_exchangeClassMethod([self class], @selector(dictionaryWithObjects:forKeys:count:), @selector(safeDictionaryWithObjects:forKeys:count:));
        
        Class clsSingleEntryDictionaryI = objc_getClass("__NSSingleEntryDictionaryI");
        hw_exchangeInstanceMethod(clsSingleEntryDictionaryI, @selector(initWithObjectsAndKeys:), @selector(safeInitWithObjectsAndKeys:));
        hw_exchangeInstanceMethod(clsSingleEntryDictionaryI, @selector(initWithObjects:forKeys:), @selector(safeInitWithObjects:forKeys:));
        
        Method system_initWithObjectsForKeysCountMethod = class_getInstanceMethod(NSClassFromString(@"__NSPlaceholderDictionary"), @selector(initWithObjects:forKeys:));
        Method cc_initWithObjectsForKeysCountMethod = class_getInstanceMethod(self, @selector(cc_initWithObjects:forKeys:));
        // 将系统方法和自己所写的方法进行替换
        method_exchangeImplementations(system_initWithObjectsForKeysCountMethod, cc_initWithObjectsForKeysCountMethod);
    });
}

- (instancetype)cc_initWithObjects:(NSArray *)objects forKeys:(NSArray<id<NSCopying>> *)keys {
    id dictionary = nil;
    @try {
        dictionary = [self cc_initWithObjects:objects forKeys:keys];
    } @catch (NSException *exception) {
        if (objects && keys) {
            NSInteger count            = objects.count > keys.count ? keys.count : objects.count;
            NSMutableArray *newObjects = [NSMutableArray arrayWithCapacity:count];
            NSMutableArray *newkeys    = [NSMutableArray arrayWithCapacity:count];
            for (NSInteger i = 0; i < count; i++) {
                if (objects[i] && keys[i]) {
                    newObjects[i] = objects[i];
                    newkeys[i]    = keys[i];
                }
            }
            dictionary = [self cc_initWithObjects:newObjects forKeys:newkeys];
        }
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return dictionary;
    }
}

- (instancetype)safeInitWithObjects:(NSArray *)objects forKeys:(NSArray<id<NSCopying>> *)keys {
    id dictionary = nil;
    @try {
        dictionary = [self safeInitWithObjects:objects forKeys:keys];
    } @catch (NSException *exception) {
        if (objects && keys) {
            NSInteger count            = objects.count > keys.count ? keys.count : objects.count;
            NSMutableArray *newObjects = [NSMutableArray arrayWithCapacity:count];
            NSMutableArray *newkeys    = [NSMutableArray arrayWithCapacity:count];
            for (NSInteger i = 0; i < count; i++) {
                if (objects[i] && keys[i]) {
                    newObjects[i] = objects[i];
                    newkeys[i]    = keys[i];
                }
            }
            dictionary = [self safeInitWithObjects:newObjects forKeys:newkeys];
        }
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return dictionary;
    }
}

- (instancetype)safeInitWithObjectsAndKeys:(id)firstObject, ... {
    NSMutableArray *objects = [[NSMutableArray alloc] init];
    va_list list;
    va_start(list, firstObject);
    [objects addObject:firstObject];
    id arg = nil;
    while ((arg = va_arg(list, id))) {
        [objects addObject:arg];
    }
    va_end(list);
    if (objects.count % 2 != 0) {
        NSException *exception = [[NSException alloc] initWithName:NSInvalidArgumentException
                                                            reason:@"-[__NSPlaceholderDictionary initWithObjectsAndKeys:]: second object of each pair must be non-nil"
                                                          userInfo:nil];
        // 收集错误信息
        hw_handleErrorWithException(exception);
    }
    // 对参数处理，丢弃最后一个参数，然后组成一个字典
    NSInteger index        = objects.count % 2 == 0 ? objects.count : objects.count - 1;
    NSMutableArray *keys   = [NSMutableArray arrayWithCapacity:objects.count / 2];
    NSMutableArray *values = [NSMutableArray arrayWithCapacity:objects.count / 2];
    for (NSInteger i = 0; i < index; i++) {
        if (i % 2 == 0) {
            [values addObject:objects[i]];
        } else {
            [keys addObject:objects[i]];
        }
    }
    return [[NSDictionary alloc] initWithObjects:[values copy] forKeys:[keys copy]];
}

+ (instancetype)safeDictionaryWithObject:(id)object forKey:(id)key {
    id dictionary = nil;
    @try {
        dictionary = [self safeDictionaryWithObject:object forKey:key];
    } @catch (NSException *exception) {
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return dictionary;
    }
}

+ (instancetype)safeDictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt {
    id dictionary = nil;
    @try {
        dictionary = [self safeDictionaryWithObjects:objects forKeys:keys count:cnt];
    } @catch (NSException *exception) {
        // 处理错误的数据，然后重新初始化一个字典
        NSUInteger index = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        id  _Nonnull __unsafe_unretained newkeys[cnt];
        for (int i = 0; i < cnt; i++) {
            if (objects[i] && keys[i]) {
                newObjects[index] = objects[i];
                newkeys[index]    = keys[i];
                index++;
            }
        }
        dictionary = [self safeDictionaryWithObjects:newObjects forKeys:newkeys count:index];
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally {
        return dictionary;
    }
}
@end

@interface NSMutableDictionary (HWStability)<HWStabilityProtocol>
@end

@implementation NSMutableDictionary (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class clsDictinaryM = objc_getClass("__NSDictionaryM");
        hw_exchangeInstanceMethod(clsDictinaryM, @selector(setObject:forKey:), @selector(safeSetObject:forKey:));
        hw_exchangeInstanceMethod(clsDictinaryM, @selector(setObject:forKeyedSubscript:), @selector(safeSetObject:forKeyedSubscript:));
        hw_exchangeInstanceMethod(clsDictinaryM, @selector(removeObjectForKey:), @selector(safeRemoveObjectForKey:));
    });
}


- (void)safeSetObject:(id)anObject forKey:(id<NSCopying>)aKey {
    @try {
        [self safeSetObject:anObject forKey:aKey];
    } @catch (NSException *exception) {
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally { }
}


- (void)safeSetObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
    @try {
        [self safeSetObject:obj forKeyedSubscript:key];
    } @catch (NSException *exception) {
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally { }
}


- (void)safeRemoveObjectForKey:(id)aKey {
    @try {
        [self safeRemoveObjectForKey:aKey];
    } @catch (NSException *exception) {
        // 收集错误信息
        hw_handleErrorWithException(exception);
    } @finally { }
}
@end

//MARK: - NSSet
@interface NSSet (HWStability)<HWStabilityProtocol>
@end

@implementation NSSet (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = objc_getClass("NSSet");
        hw_exchangeClassMethod(cls, @selector(setWithObject:), @selector(safeSetWithObject:));
    });
}

+ (instancetype)safeSetWithObject:(id)object {
    id instance = nil;
    @try {
        instance = [self safeSetWithObject:object];
    } @catch (NSException *exception) {
       hw_handleErrorWithException(exception);
    } @finally {
        return instance;
    }
}

@end

@interface NSMutableSet (HWStability)<HWStabilityProtocol>
@end

@implementation NSMutableSet (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = objc_getClass("NSMutableSet");
        hw_exchangeInstanceMethod(cls, @selector(addObject:), @selector(safeddObject:));
        hw_exchangeInstanceMethod(cls, @selector(removeObject:), @selector(safeRemoveObject:));
    });
}


- (void)safeddObject:(id)object {
    @try {
        [self safeddObject:object];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally { }
}

- (void)safeRemoveObject:(id)object {
    @try {
        [self safeRemoveObject:object];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally { }
}

@end

//MARK: - NSString
@interface NSString (HWStability)<HWStabilityProtocol>
@end

@implementation NSString (HWStability)
+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = objc_getClass("NSString");
        hw_exchangeClassMethod(cls, @selector(stringWithUTF8String:), @selector(safeStringWithUTF8String:));
        hw_exchangeClassMethod(cls, @selector(stringWithCString:encoding:), @selector(safeStringWithCString:encoding:));
        
        Class clsPlaceholderString = objc_getClass("NSPlaceholderString");
        hw_exchangeInstanceMethod(clsPlaceholderString, @selector(initWithCString:encoding:), @selector(safeInitWithCString:encoding:));
        hw_exchangeInstanceMethod(clsPlaceholderString, @selector(initWithString:), @selector(safeInitWithString:));
        
        
        Class clsNSCFConstantString = objc_getClass("__NSCFConstantString");
        hw_exchangeInstanceMethod(clsNSCFConstantString, @selector(substringFromIndex:), @selector(safeSubstringFromIndex:));
        hw_exchangeInstanceMethod(clsNSCFConstantString, @selector(substringToIndex:), @selector(safeSubstringToIndex:));
        hw_exchangeInstanceMethod(clsNSCFConstantString, @selector(substringWithRange:), @selector(safeSubstringWithRange:));
        hw_exchangeInstanceMethod(clsNSCFConstantString, @selector(rangeOfString:options:range:locale:), @selector(safeRangeOfString:options:range:locale:));
        
        
        Class clsTaggedPointerString = objc_getClass("NSTaggedPointerString");
        hw_exchangeInstanceMethod(clsTaggedPointerString, @selector(substringFromIndex:), @selector(safeSubstringFromIndex:));
        hw_exchangeInstanceMethod(clsTaggedPointerString, @selector(substringToIndex:), @selector(safeSubstringToIndex:));
        hw_exchangeInstanceMethod(clsTaggedPointerString, @selector(substringWithRange:), @selector(safeSubstringWithRange:));
        hw_exchangeInstanceMethod(clsTaggedPointerString, @selector(rangeOfString:options:range:locale:), @selector(safeRangeOfString:options:range:locale:));
    });
}



+ (NSString *)safeStringWithUTF8String:(const char *)nullTerminatedCString {
    NSString *string = nil;
    @try {
        string = [self safeStringWithUTF8String:nullTerminatedCString];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}

+ (nullable instancetype)safeStringWithCString:(const char *)cString encoding:(NSStringEncoding)enc {
    NSString *string = nil;
    @try {
        string = [self safeStringWithCString:cString encoding:enc];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}

- (nullable instancetype)safeInitWithString:(id)cString {
    NSString *string = nil;
    @try {
        string = [self safeInitWithString:cString];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}

- (nullable instancetype)safeInitWithCString:(const char *)nullTerminatedCString encoding:(NSStringEncoding)encoding {
    NSString *string = nil;
    @try {
        string = [self safeInitWithCString:nullTerminatedCString encoding:encoding];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}

- (NSString *)safeSubstringFromIndex:(NSUInteger)from {
    NSString *string = self;
    @try {
        string = [self safeSubstringFromIndex:from];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}

- (NSString *)safeSubstringToIndex:(NSUInteger)to {
    NSString *string = self;
    @try {
        string = [self safeSubstringToIndex:to];
    } @catch (NSException *exception) {
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}

- (NSString *)safeSubstringWithRange:(NSRange)range {
    NSString *string = self;
    @try {
        string = [self safeSubstringWithRange:range];
    } @catch (NSException *exception) {
        // 如果是起点在字符串内，但是长度超过字符串，就返回起点之后的字符
        if (range.location < self.length) {
            string = [self safeSubstringWithRange:NSMakeRange(range.location, self.length - 1 - range.location)];
        }
        hw_handleErrorWithException(exception);
    } @finally {
        return string;
    }
}
- (NSRange)safeRangeOfString:(NSString *)searchString
                     options:(NSStringCompareOptions)mask
                       range:(NSRange)range
                      locale:(nullable NSLocale *)locale {
    NSRange returnRange;
    @try {
        returnRange = [self safeRangeOfString:searchString options:mask range:range locale:locale];
    } @catch (NSException *exception) {
        if (searchString && range.location < self.length) {
            NSRange safeRange = NSMakeRange(range.location, self.length - 1 - range.location);
            returnRange       =  [self safeRangeOfString:searchString
                                                 options:mask
                                                   range:safeRange
                                                  locale:locale];
        }
        hw_handleErrorWithException(exception);
    } @finally {
        return returnRange;
    }
}

@end


//MARK: - NSTimer
@interface HWTimerTagetAgent : NSObject

@property (nonatomic, assign) NSTimeInterval ti;
@property (nonatomic, weak)   id             target;
@property (nonatomic, assign) SEL            selector;
@property (nonatomic, assign) id             userInfo;
@property (nonatomic, weak)   NSTimer        *timer;
@property (nonatomic, copy)   NSString       *targetClassName;
@property (nonatomic, copy)   NSString       *targetMethodName;

@end


@implementation HWTimerTagetAgent

- (void)fireTimer {
    if (!self.target) {
        [self.timer invalidate];
        self.timer = nil;
        NSString *reason = [NSString stringWithFormat:@"In [%@ %@], a instance has release, but the timer has not invalidate", self.targetClassName, self.targetMethodName];
        NSException *exception = [[NSException alloc] initWithName:@"NSTimer Exception"
                                                            reason:reason
                                                          userInfo:nil];
        hw_handleErrorWithException(exception);
        return;
    }
    if ([self.target respondsToSelector:self.selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
        [self.target performSelector:self.selector withObject:self.timer];
#pragma clang diagnostic pop
    }
}

@end

@interface NSTimer (HWStability)<HWStabilityProtocol>

@end

@implementation NSTimer (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        hw_exchangeClassMethod([NSTimer class], @selector(scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:), @selector(safeScheduledTimerWithTimeInterval:target:selector:userInfo:repeats:));
    });
}

+ (NSTimer *)safeScheduledTimerWithTimeInterval:(NSTimeInterval)ti
                                         target:(id)aTarget
                                       selector:(SEL)aSelector
                                       userInfo:(nullable id)userInfo
                                        repeats:(BOOL)yesOrNo {
    if (!yesOrNo) {
        return [self safeScheduledTimerWithTimeInterval:ti
                                                 target:aTarget
                                               selector:aSelector
                                               userInfo:userInfo
                                                repeats:yesOrNo];
    }
    HWTimerTagetAgent *agent = [HWTimerTagetAgent new];
    agent.ti               = ti;
    agent.target           = aTarget;
    agent.selector         = aSelector;
    agent.userInfo         = userInfo;
    if (aTarget) {
        agent.targetClassName = [NSString stringWithCString:object_getClassName(aTarget)
                                                   encoding:NSASCIIStringEncoding];
    }
    agent.targetMethodName    = NSStringFromSelector(aSelector);
    NSTimer *timer = [NSTimer safeScheduledTimerWithTimeInterval:ti
                                                          target:agent
                                                        selector:@selector(fireTimer)
                                                        userInfo:userInfo
                                                         repeats:yesOrNo];
    agent.timer = timer;
    return timer;
}

@end

//MARK: - UIView
@interface UIView (HWStability)<HWStabilityProtocol>

@end

@implementation UIView (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class cls = objc_getClass("UIView");
        hw_exchangeInstanceMethod(cls, @selector(setNeedsLayout), @selector(safeSetNeedsLayout));
        hw_exchangeInstanceMethod(cls, @selector(setNeedsDisplay), @selector(safeSetNeedsDisplay));
        hw_exchangeInstanceMethod(cls, @selector(setNeedsDisplayInRect:), @selector(safeSetNeedsDisplayInRect:));
    });
}


- (void)safeSetNeedsLayout {
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self safeSetNeedsLayout];
        });
#if DEBUG
        NSString *message = [NSString stringWithFormat:@"You can not display UI on a background thread,-[%@ safeSetNeedsLayout]", [self class]];
        NSAssert(false, message);
#endif
    }
    [self safeSetNeedsLayout];
}

- (void)safeSetNeedsDisplay {
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self safeSetNeedsDisplay];
        });
#if DEBUG
        NSString *message = [NSString stringWithFormat:@"You can not display UI on a background thread,-[%@ safeSetNeedsDisplay]", [self class]];
        NSAssert(false, message);
#endif
    }
    [self safeSetNeedsDisplay];
}

- (void)safeSetNeedsDisplayInRect:(CGRect)rect {
    if (![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self safeSetNeedsDisplayInRect:rect];
        });
#if DEBUG
        NSString *message = [NSString stringWithFormat:@"You can not display UI on a background thread,-[%@ safeSetNeedsDisplayInRect:]", [self class]];
        NSAssert(false, message);
#endif
    }
    [self safeSetNeedsDisplayInRect:rect];
}
@end
//MARK: - NSObject
static const char DeallocKVOKey;
static const char ObserverDeallocKVOKey;

@interface KVOObjectItem : NSObject

@property (nonatomic, strong) NSObject                   *observer;
@property (nonatomic, copy)   NSString                   *keyPath;
@property (nonatomic, assign) NSKeyValueObservingOptions options;
@property (nonatomic, assign) void                       *context;

@end

@implementation KVOObjectItem

- (BOOL)isEqual:(KVOObjectItem *)object {
    if ([self.observer isEqual:object.observer]
        && [self.keyPath isEqualToString:object.keyPath]) return YES;
    
    return NO;
}

- (NSUInteger)hash {
    return [self.observer hash] ^ [self.keyPath hash];
}

@end


@interface KVOObjectContainer : NSObject

@property (nonatomic, retain)            NSMutableSet         *kvoObjectSet;
@property (nonatomic, unsafe_unretained) NSObject             *whichObject;
#if OS_OBJECT_HAVE_OBJC_SUPPORT
@property (nonatomic, retain)            dispatch_semaphore_t kvoLock;
#else
@property (nonatomic, assign)            dispatch_semaphore_t kvoLock;
#endif

- (void)addKVOObjectItem:(KVOObjectItem *)item;
- (void)removeKVOObjectItem:(KVOObjectItem *)item;
- (BOOL)checkKVOItemExist:(KVOObjectItem *)item;

@end

@implementation KVOObjectContainer

- (void)addKVOObjectItem:(KVOObjectItem *)item {
    if (item) {
        dispatch_semaphore_wait(self.kvoLock, DISPATCH_TIME_FOREVER);
        [self.kvoObjectSet addObject:item];
        dispatch_semaphore_signal(self.kvoLock);
    }
}

- (void)removeKVOObjectItem:(KVOObjectItem *)item {
    if (item) {
        dispatch_semaphore_wait(self.kvoLock, DISPATCH_TIME_FOREVER);
        [self.kvoObjectSet removeObject:item];
        dispatch_semaphore_signal(self.kvoLock);
    }
}

- (BOOL)checkKVOItemExist:(KVOObjectItem *)item {
    dispatch_semaphore_wait(self.kvoLock, DISPATCH_TIME_FOREVER);
    BOOL exist = NO;
    if (!item) {
        dispatch_semaphore_signal(self.kvoLock);
        return exist;
    }
    exist = [self.kvoObjectSet containsObject:item];
    dispatch_semaphore_signal(self.kvoLock);
    return exist;
}

- (dispatch_semaphore_t)kvoLock {
    if (!_kvoLock) {
        _kvoLock = dispatch_semaphore_create(1);
        return _kvoLock;
        
    }
   
    return _kvoLock;
}


- (void)cleanKVOData {
    for (KVOObjectItem *item in self.kvoObjectSet) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
        @try {
            ((void(*)(id, SEL, id, NSString *))objc_msgSend)(self.whichObject, @selector(hookRemoveObserver:forKeyPath:), item.observer, item.keyPath);
        } @catch (NSException *exception) {

        }
#pragma clang diagnostic pop
    }
}

- (NSMutableSet *)kvoObjectSet {
    if (!_kvoObjectSet) {
        _kvoObjectSet = [[NSMutableSet alloc] init];
    }
    return _kvoObjectSet;
}

@end

@interface HYObserverContainer : NSObject

@property (nonatomic, retain) NSHashTable *observers;
@property (nonatomic, assign) NSObject *whichObject;

- (void)addObserver:(KVOObjectItem *)observer;
- (void)removeObserver:(KVOObjectItem *)observer;

@end

@implementation HYObserverContainer

- (instancetype)init {
    if (self = [super init]) {
        self.observers = [NSHashTable hashTableWithOptions:NSMapTableWeakMemory];
    }
    return self;
}

- (void)addObserver:(KVOObjectItem *)observer {
    @synchronized (self) {
        [self.observers addObject:observer];
    }
}

- (void)removeObserver:(KVOObjectItem *)observer {
    @synchronized (self) {
        [self.observers removeObject:observer];
    }
}

- (void)cleanObservers {
    for (KVOObjectItem *item in self.observers) {
        [self.whichObject removeObserver:item.observer forKeyPath:item.keyPath];
    }
    @synchronized (self) {
        [self.observers removeAllObjects];
    }
}

@end

@interface NSObject (HWStability)<HWStabilityProtocol>
@end

@implementation NSObject (HWStability)

+ (void)hw_swizzleMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
#if DEBUG // debug 模式下监控
        //MARK: 调用未被实例化的方法崩溃优化
        hw_exchangeInstanceMethod(self, @selector(methodSignatureForSelector:), @selector(safemethodSignatureForSelector:));
        hw_exchangeInstanceMethod(self, @selector(forwardInvocation:), @selector(safeforwardInvocation:));
        //MARK: KVO方法崩溃优化
        hw_exchangeInstanceMethod(self, @selector(addObserver:forKeyPath:options:context:), @selector(safeAddObserver:forKeyPath:options:context:));
        hw_exchangeInstanceMethod(self, @selector(removeObserver:forKeyPath:), @selector(safeRemoveObserver:forKeyPath:));
        hw_exchangeInstanceMethod(self, @selector(removeObserver:forKeyPath:context:), @selector(safeRemoveObserver:forKeyPath:context:));
#endif
    });
}


- (NSMethodSignature *)safemethodSignatureForSelector:(SEL)aSelector {
    //    [self safemethodSignatureForSelector:aSelector];
    //    NSString *sel = NSStringFromSelector(aSelector);
    //    if ([sel rangeOfString:@"set"].location == 0) {
    //        return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
    //    } else {
    //        return [NSMethodSignature signatureWithObjCTypes:"@@:"];
    //    }
    NSMethodSignature *methodSignature = [self safemethodSignatureForSelector:aSelector];
    if (methodSignature) return methodSignature;
    IMP originIMP       = class_getMethodImplementation([NSObject class], @selector(methodSignatureForSelector:));
    IMP currentClassIMP = class_getMethodImplementation([self class],     @selector(methodSignatureForSelector:));
    // 如果子类重载了该方法，则返回nil
    if (originIMP != currentClassIMP) return nil;
    // - (void)xxxx
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}

//需要重写这个方法才会避免崩溃
- (void)safeforwardInvocation:(NSInvocation *)anInvocation {
#if DEBUG // debug 模式下监控 避免交互方法导致系统方法异常
    NSString *reason = [NSString stringWithFormat:@"class:[%@] not found selector:(%@)",NSStringFromClass(self.class),NSStringFromSelector(anInvocation.selector)];
    NSException *exception = [NSException exceptionWithName:@"Unrecognized Selector"
                                                     reason:reason
                                                   userInfo:nil];
    // 收集错误信息
    hw_handleErrorWithException(exception);
#endif
}


- (void)safeAddObserver:(NSObject *)observer
             forKeyPath:(NSString *)keyPath
                options:(NSKeyValueObservingOptions)options
                context:(void *)context {
    if ([self ignoreKVOInstanceClass:observer]) {
        [self safeAddObserver:observer
                   forKeyPath:keyPath
                      options:options
                      context:context];
        return;
    }
    if (!observer || keyPath.length == 0) return;
    KVOObjectContainer *objectContainer = objc_getAssociatedObject(self, &DeallocKVOKey);
    KVOObjectItem *item = [[KVOObjectItem alloc] init];
    item.observer       = observer;
    item.keyPath        = keyPath;
    item.options        = options;
    item.context        = context;
    if (!objectContainer) {
        objectContainer = [[KVOObjectContainer alloc] init];
        [objectContainer setWhichObject:self];
        objc_setAssociatedObject(self, &DeallocKVOKey, objectContainer, OBJC_ASSOCIATION_RETAIN);
    }
    if (![objectContainer checkKVOItemExist:item]) {
        [objectContainer addKVOObjectItem:item];
        [self safeAddObserver:observer
                   forKeyPath:keyPath
                      options:options
                      context:context];
    }
    HYObserverContainer *observerContainer = objc_getAssociatedObject(observer, &ObserverDeallocKVOKey);
    if (!observerContainer) {
        observerContainer = [[HYObserverContainer alloc] init];
        [observerContainer setWhichObject:self];
        [observerContainer addObserver:item];
        objc_setAssociatedObject(observer, &ObserverDeallocKVOKey, observerContainer, OBJC_ASSOCIATION_RETAIN);
    } else {
        [observerContainer addObserver:item];
    }
}

- (void)safeRemoveObserver:(NSObject *)observer
                forKeyPath:(NSString *)keyPath
                   context:(void *)context {
    if ([self ignoreKVOInstanceClass:observer]) {
        [self safeRemoveObserver:observer
                      forKeyPath:keyPath
                         context:context];
        return;
    }
    [self removeObserver:observer forKeyPath:keyPath];
}

- (void)safeRemoveObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
    if ([self ignoreKVOInstanceClass:observer]) {
        [self safeRemoveObserver:observer forKeyPath:keyPath];
        return;
    }
    
    KVOObjectContainer *objectContainer = objc_getAssociatedObject(self, &DeallocKVOKey);
    if (!observer || !objectContainer) return;
    KVOObjectItem *item = [[KVOObjectItem alloc] init];
    item.observer       = observer;
    item.keyPath        = keyPath;
    if ([objectContainer checkKVOItemExist:item]) {
        @try {
            [self safeRemoveObserver:observer forKeyPath:keyPath];
        }
        @catch (NSException *exception) {
            hw_handleErrorWithException(exception);
        }
        [objectContainer removeKVOObjectItem:item];
    } else {
        NSException *exception = [[NSException alloc] initWithName:@""
                                                            reason:@""
                                                          userInfo:nil];
        hw_handleErrorWithException(exception);
    }
}

- (BOOL)ignoreKVOInstanceClass:(id)object {
    if (!object) return NO;
    // Ignore ReactiveCocoa
    if (object_getClass(object) == objc_getClass("RACKVOProxy")) return YES;
    // Ignore AMAP
    NSString *className = NSStringFromClass(object_getClass(object));
    if ([className hasPrefix:@"AMap"]) return YES;
    return NO;
}

- (void)cc_cleanKVO {
    KVOObjectContainer *objectContainer    = objc_getAssociatedObject(self, &DeallocKVOKey);
    HYObserverContainer *observerContainer = objc_getAssociatedObject(self, &ObserverDeallocKVOKey);
    if (objectContainer) {
        [objectContainer cleanKVOData];
    } else if (observerContainer) {
        [observerContainer cleanObservers];
    }
}

@end
